#ifndef __ILIB_UTIL_STREAM_H_20120402__
#define __ILIB_UTIL_STREAM_H_20120402__

#include <sstream>
#include "iMsgDB.h"
#if defined(__WIN__)
#elif defined(__LINUX__)
#include <sys/time.h>
#endif

class iStream
{
protected:
	iStream(iMsgDB* mbs=NULL)
		:m_buffer(mbs)
		,m_is_good(true)
	{
	}
	virtual ~iStream()
	{
		if(m_buffer)
			m_buffer->release();
		m_buffer = NULL;
	}
	
	inline uint32_t read(uint8_t* buf, uint32_t len)
	{
		m_is_good = m_buffer!=NULL;
		if(!good())
			return 0;

		uint32_t cnt = m_buffer->read(buf, len);
		m_is_good = cnt==len;
		return cnt;
	}
	inline uint32_t write(uint8_t* buf, uint32_t len)
	{
		m_is_good = m_buffer!=NULL;
		if(!good())
			return 0;

		uint32_t cnt = m_buffer->write(buf, len);
		m_is_good = cnt==len;
		return cnt;
	}

public:
	inline uint32_t length() { return m_buffer->get_total_data_length();}
	inline bool good() { return m_is_good; }
	inline iMsgDB* get_msg_db() { return m_buffer; }

protected:
	iMsgDB* m_buffer;
	bool m_is_good;
};
class iInputStream : public iStream
{
public:
	inline iInputStream(iMsgDB* mbs) : iStream(mbs){ m_is_good=mbs!=NULL;}
    virtual ~iInputStream(){}
	inline iInputStream& operator>>(int8_t& v)  { read(&v, sizeof(v)); return *this;}
	inline iInputStream& operator>>(uint8_t& v) { read(&v,sizeof(v)); return *this;}
	inline iInputStream& operator>>(int16_t& v) { read(&v, sizeof(v)); return *this;}
	inline iInputStream& operator>>(uint16_t& v){ read(&v, sizeof(v)); return *this;}
	inline iInputStream& operator>>(int32_t& v) { read(&v, sizeof(v)); return *this;}
	inline iInputStream& operator>>(uint32_t& v){ read(&v,sizeof(v)); return *this; }
	inline iInputStream& operator>>(std::string& v) 
	{
		if(!m_is_good) 
			return *this;

		uint32_t len = 0;
		*this >> len;
		m_is_good = len <= length();
		if(good()) 
		{
			char* data = new char[len+1];
			read(data, len);
			data[len] = 0;
			v = data;
			delete []data;
		}
		return *this;
	}

	inline uint32_t read(void* buf, uint32_t len)
	{		
		if(!m_is_good) 
			return 0;

		return iStream::read((uint8_t*)buf, len);
	}
};
class iOutputStream : public iStream
{
public:
	inline iOutputStream(iMsgDB* mbs=NULL) : iStream(mbs) { if(m_buffer == NULL) m_buffer = iMsgDB::new_instance(NULL, 512); }
    virtual ~iOutputStream(){}
	inline iOutputStream& operator<<(int8_t v) { write(&v,sizeof(v)); return *this;}
	inline iOutputStream& operator<<(uint8_t v) { write(&v, sizeof(v)); return *this; }
	inline iOutputStream& operator<<(int16_t v){ write(&v, sizeof(v)); return *this; }
	inline iOutputStream& operator<<(uint16_t v){write(&v,sizeof(v)); return *this;}
	inline iOutputStream& operator<<(int32_t v){write(&v,sizeof(v)); return *this; }
	inline iOutputStream& operator<<(uint32_t v){write(&v,sizeof(v)); return *this; }
	inline iOutputStream& operator<<(const char* v) 
	{
		uint32_t len = strlen(v);
		*this << len;
		write((uint8_t*)v, len);
		return *this;
	}
	inline iOutputStream& operator<<(std::string& v)
	{
		uint32_t len = v.length();
		*this << len;
		write((uint8_t*)v.c_str(), len);
		return *this;
	};

	inline uint32_t write(void* buf, uint32_t len)
	{
		return iStream::write((uint8_t*)buf, len);
	}
};
class iLogStream
{
public:
	inline void open(const char* dir, const char* name)
	{
		if(!m_file_prefix.empty())
			return;

		m_file_prefix = dir;
		m_file_prefix += "/";
		m_file_prefix += name;
		m_index = 0;
		m_fd = NULL;
		m_lines = 0;

		open_i();
	}
	inline void close()
	{
		fclose(m_fd);
		m_lines = 0;
	}
	inline void write(const char* module, const char* level, uint32_t pid, uint32_t tid, const char* content)
	{
		#if defined(__WIN__)
		SYSTEMTIME sys;
		GetLocalTime( &sys );
		fprintf(m_fd, "[%4d-%02d-%02d %02d:%02d:%02d.%03d]\t%s\t[%d:%d]\t%s\t%s\n",	sys.wYear, 
																			sys.wMonth, 
																			sys.wDay, 
																			sys.wHour, 
																			sys.wMinute, 
																			sys.wSecond, 
																			sys.wMilliseconds,
																			module,
                                                                            tid,
                                                                            pid,
																			level,
																			content);
		#elif defined(__LINUX__)
		timeval tv;
		tm tme;
		gettimeofday(&tv, NULL);
		localtime_r(&tv.tv_sec, &tme);
		fprintf(m_fd, "[%4d-%02d-%02d %02d:%02d:%02d.%03d]\t%s\t[%d:%d]\t%s\t%s\n",	tme.tm_year+1900, 
																			tme.tm_mon, 
																			tme.tm_mday, 
																			tme.tm_hour, 
																			tme.tm_min, 
																			tme.tm_sec, 
																			(uint32_t)tv.tv_usec/1000,
																			module,
                                                                            tid,
                                                                            pid,
																			level,
																			content);
		#endif
		m_lines++;
		if(m_lines>200000)
		{
			close();
			open_i();
		}
		else
			fflush(m_fd);
	}
	uint32_t get_line_count() { return m_lines; }

private:
	inline void open_i()
	{
		char post_fix[128] = {0};
#if defined(__WIN__)
		SYSTEMTIME sys;
		GetLocalTime( &sys );
		sprintf(post_fix, "_%4d%02d%02d_%d.log",sys.wYear, 
												sys.wMonth, 
												sys.wDay, 
												m_index++);
#elif defined(__LINUX__)
		timeval tv;
		tm tme;
		gettimeofday(&tv, NULL);
		localtime_r(&tv.tv_sec, &tme);
		sprintf(post_fix, "_%4d%02d%02d_%d.log",tme.tm_year+1900, 
												tme.tm_mon, 
												tme.tm_mday, 
												m_index++);
#endif
		if(m_index>10)
			m_index = 0;
		std::string full_path = m_file_prefix+post_fix;
		m_fd = fopen(full_path.c_str(), "w+");
		m_lines = 0;
	}

private:
	std::string m_file_prefix;
	uint32_t	m_index; 
	uint32_t	m_lines;
	FILE*		m_fd;
};
#endif  //__ILIB_UTIL_STREAM_H_20120402__
